%% GUI function for the TRAVEL model, calls all other functions
% 
% input: user input of values defined in the function
% output: sends gui and cfg values to MainFunction
%
% Used the call the nescesary GUI components, or automatically loops over
% subfunctions of the model (automate).
% Defines many of the configuration parameters through the GUI elements
% e.g. gui.h.ex=..(...,'Value',1) will be read out as one, a 'String'
% element will be read out as a string. 
% Play button starts the model (calls RunTravel), Stop stops the model, load output loads the
% last model into workspace. Checkboxes switch are 0 or 1, textboxes can
% have multiple elements seperated by spaces, e.g. 1 3 5 for a vector [1 3
% 5] in the model.
% runtravel

function StartModel
%% Starting function, allows for automated looping if needed
automate = 'no';

switch automate
    case 'yes'
        for m=[1 26]
        for n=1:10
            Mainbody('AllRegions',1,'nogui')
        end
        end
    case 'no'
        Mainbody
end
end

function Mainbody(varargin)
%% Creates the Graphical User Interface
gui.nobuttons        = [4 8];       
gui.buttondistance   = [20 10];
gui.buttonsize       = [120 45];
gui.figuresize       = (gui.buttonsize+gui.buttondistance).*(gui.nobuttons)+gui.buttondistance;
gui.uipositions(:,1) = sort(repmat(round(linspace(gui.buttondistance(1),gui.figuresize(1)-gui.buttondistance(1)-gui.buttonsize(1),gui.nobuttons(1))'),gui.nobuttons(2),1));
gui.uipositions(:,2) = repmat(round(linspace(gui.buttondistance(2),gui.figuresize(2)-gui.buttondistance(2)-gui.buttonsize(2),gui.nobuttons(2))'),gui.nobuttons(1),1);

if ~isempty(varargin) && isa(varargin{1},'double')
    varargin={}; gui.source = 'popupmenu';
end
if ~isfield(gui,'fid');
    gui.fid          = figure(3);
    set(gui.fid,'name','Timer-Travel Modelling framework, (c) Roel Stijl','numbertitle','off')
    set(gui.fid,'position',[50 50 gui.figuresize]); else figure(gui.fid);
end

%% Builds the gui controls
if ~isfield(gui,'source');
    
gui.h.NoRuns                = uicontrol('String','1','Style','edit');
gui.h.CalibrationYears      = uicontrol('String','1:35','Style','edit');
gui.h.CalculatedRegions     = uicontrol('String',num2str([12]),'Style','edit');
gui.h.NumberofCPUCores      = uicontrol('String',num2str([7]),'Style','edit');

gui.h.ParallelComputing     = uicontrol('Style','checkbox','value',0); % Use Parallel computing
gui.h.AllRegions            = uicontrol('Style','checkbox','value',0); % Calculate all regions
gui.h.NoUnMotorized         = uicontrol('Style','checkbox','value',0); % Calculate all regions
gui.h.VanRuijvenMonteCarlo  = uicontrol('Style','checkbox','value',0); % Calculate all regions

% Calculation options
gui.h.NoOptimization        = uicontrol('Style','checkbox','value',0); % Skip the optimization step
gui.h.MonteCarloSimulation  = uicontrol('Style','checkbox','value',0); % Enable Monte Carlo
gui.h.EnableLinearPF        = uicontrol('Style','checkbox','value',1); % Linearize (i.e. y=ax+b) PF calibration
gui.h.GeneticSolverT0       = uicontrol('Style','checkbox','value',1); % Determines starting conditions with genetic (global) algorithm

gui.h.FutureProjection      = uicontrol('Style','checkbox','value',1); % Enable projections
gui.h.LoopOverVariables     = uicontrol('Style','checkbox','value',0); % Disable check on final GA solution
gui.h.ConvergencePFandSW    = uicontrol('Style','checkbox','value',1); % Enable projections
gui.h.Placeholder1          = uicontrol('Style','checkbox','value',0); % Disable check on final GA solution

% Plotting options
gui.h.UpdateGUIPlot         = uicontrol('Style','checkbox','value',0); % Update the GUI plots (is time consuming)
gui.h.SensitivityAnalysis   = uicontrol('Style','checkbox','value',0); % Sensitivty analysis after calibration
gui.h.PlotMinimize          = uicontrol('Style','checkbox','value',0); % Plots the errors of the calibration step after calibration
gui.h.LiveMinimationVisual  = uicontrol('Style','checkbox','value',0); % Shows the development of calibration, live

gui.h.RestrictTWRange       = uicontrol('Style','checkbox','value',1); % Restricts the allowed values of TimeWeight in the GA solution
gui.h.CalibrateCostDistrParameter = uicontrol('Style','checkbox','value',0); % Calibrate the CostDistrParameter for GCAM

gui.h.Solver                = uicontrol('Style','popupmenu','String',{'fminsearchbnd','fmincon','fminbnd','fminsearch','lsqnonlin','ga','None'},'Value',1);
gui.h.Model                 = uicontrol('Style','popupmenu','String',{'ModelTravelLinearTW','ModelTravelOptimizedTW','ModelPoles','ModelSimple','ModelGcam'});
gui.h.Dataset               = uicontrol('Style','popupmenu','String',{'exvars 1971-2100 Original Dataset Regions11Modes4.mat','exvars 1971-2100 Constant Speed Regions11Modes4.mat','exvars 1971-2100 Original Dataset Regions26Modes7.mat','exvars 1971-2100 Constant Speed Regions26Modes7.mat','exvars 1971-2005 Original Dataset.mat'});
gui.h.RegionSet             = uicontrol('Style','popupmenu','String',{'regions26','regions11','regions3'},'Value',2);
gui.h.ModeSet               = uicontrol('Style','popupmenu','String',{'modes7','modes4','modes3'},'Value',2);
gui.h.plotmode              = uicontrol('Style','popupmenu','String',{'None','AllYearsPlot','HistoricPlot','Barplot errors','TTB and TMB' ,'ProjectionArea','Regression and Scatter','Sensitivity Analysis','PF or SW over time','Send to Workspace'});

gui.h.ProcessData           = uicontrol('Style','pushbutton','String','Process Data','CallBack',@PostProcessData);
gui.h.LoadDataFromXLSX      = uicontrol('Style','pushbutton','String','Reload data from XLSX files','CallBack',@LoadXLSXData);
gui.h.LoadLastRun           = uicontrol('Style','pushbutton','String','Load last run data','CallBack',@loadlastrun);

% gui.h.Regions               = uicontrol('Style','slider','Min',1,'Max',26,'Value',1,'SliderStep',[1/25 5/25],'String','run');
gui.h.OutputFolder          = uicontrol('Style','edit','String',['test/' datestr(now,'yyyy-mm-dd_HH-MM-SS')]);
gui.h.OutputFile            = uicontrol('Style','edit','String','');

gui.h.Info                  = uicontrol('Style','text','String',{'Region / Time / Run: ',['- / - / -']},'value',1);
gui.h.Play                  = uicontrol('Style','togglebutton','String','Play');

end

gui.cfg.startdate           = get(gui.h.OutputFolder,'String');

% Checks for nogui toggle
if ~isempty(varargin); for n=1:2:length(varargin)
        if ~isequal(varargin{n},'nogui')
    set(gui.h.(char(varargin{n})),'Value',varargin{n+1}); end; end;
end

%% Modify GUI positions
gui.uifields          = fieldnames(gui.h);
gui.checkboxcount     = 1; n=1; m=1;
while n<=length(gui.uifields);
switch get(gui.h.(char(gui.uifields(n,:))),'Style')
    case 'checkbox'
        set(gui.h.(char(gui.uifields(n,:))),'String',char(gui.uifields(n,:)),'position',[gui.uipositions(m,1) gui.uipositions(m,2)+gui.buttonsize(2)*mod(gui.checkboxcount+1,2)/2 gui.buttonsize(1) gui.buttonsize(2)/2]);
        m=m-mod(gui.checkboxcount,2); gui.checkboxcount = gui.checkboxcount+1;
        if ~isequal(get(gui.h.(char(gui.uifields(n+1,:))),'Style'),'checkbox')&&mod(m,2)~=0; m=m+1; end
    case {'edit'}
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize(1),gui.buttonsize(2)/2]);
        uicontrol('Style','text','String',char(gui.uifields(n,:)),'position',[gui.uipositions(m,1) gui.uipositions(m,2)+gui.buttonsize(2)/2 gui.buttonsize(1) gui.buttonsize(2)/2],'Backgroundcolor',get(gui.fid,'color'))
    case {'popupmenu'}
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize(1),gui.buttonsize(2)/2]);
        uicontrol('Style','text','String',char(gui.uifields(n,:)),'position',[gui.uipositions(m,1) gui.uipositions(m,2)+gui.buttonsize(2)/2 gui.buttonsize(1) gui.buttonsize(2)/2],'Backgroundcolor',get(gui.fid,'color'))
        curstrings = get(gui.h.(char(gui.uifields(n,:))),'String');
        if isequal('Specify',char(curstrings(get(gui.h.(char(gui.uifields(n,:))),'Value'),:))); 
            gui.s.(char(gui.uifields(n,:))) = specifygui(gui.h.(char(gui.uifields(n,:)))); end
    case 'pushbutton'
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize]);
    otherwise
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize]);
end
    set(gui.h.(char(gui.uifields(n,:))),'Backgroundcolor',get(gui.fid,'color'));
    n=n+1; m=m+1;
end

if get(gui.h.UpdateGUIPlot,'Value')==1
subplot(2,2,2);
title('Error')

subplot(2,2,4);
title('TravelDemand')
end

%% Send handles to configuration
if sum(strcmp('nogui',varargin))==1;         % GUI off
    gui.nogui = true;
    disp('NoGUI toggle found, automated run');
    pause(2);
    set(gui.fid,'Visible','off');
    RunModel(gui.h.Play,1);
end

RunModel([],gui);


end

function RunModel(guihandle,event)
%% Loads the gui controls into cfg and runs the model
persistent gui

if isempty(guihandle)
gui         = event;
set(gui.h.Play,'CallBack',@RunModel,'Value',0);
else

%% Read out gui values
set(gui.h.Play,'CallBack',@RunModel,'Value',0);
cfg.h = gui.h;
for n=1:length(gui.uifields)
switch get(gui.h.(char(gui.uifields(n,:))),'Style')
    case 'checkbox'
        cfg.(char(gui.uifields(n,:))) = get(gui.h.(char(gui.uifields(n,:))),'Value');
    case 'edit'
        if sum(isletter(get(gui.h.(char(gui.uifields(n,:))),'String'))) == 0
            cfg.(char(gui.uifields(n,:))) = eval(['[' get(gui.h.(char(gui.uifields(n,:))),'String') ']']);
        else
            cfg.(char(gui.uifields(n,:))) = get(gui.h.(char(gui.uifields(n,:))),'String');
        end
        
    case 'popupmenu'
        temp.popup                    = get(gui.h.(char(gui.uifields(n,:))),'String');
        cfg.(char(gui.uifields(n,:))) = temp.popup(get(gui.h.(char(gui.uifields(n,:))),'Value'),:);
        cfg.(char(gui.uifields(n,:))) = cfg.(char(gui.uifields(n,:))){1};
    otherwise
        cfg.(char(gui.uifields(n,:))) = get(gui.h.(char(gui.uifields(n,:))),'Value');
end
end

MainFunction(cfg,gui);
end
end

function loadlastrun(handle,event)
%% Loads the last saved dataset if button is pressed
    set(handle,'Value',0);
    folders = dir('Output/Test');
    folderdate = 1:length(folders);

    for n=1:length(folders)
        folderdate(n) = folders(n).datenum;
    end
    
    files = dir (['Output/Test/' folders(folderdate==max(folderdate)).name '/*.mat']);
    
    for n=1:length(files)
        filedate(n) = files(n).datenum;
    end    
    
    fullpath = ['Output/Test/' folders(folderdate==max(folderdate)).name '/'  files(filedate==max(filedate)).name];
    evalin('base',['load ' fullpath]);
    disp(['Loaded: ' 'Output/Test/' folders(folderdate==max(folderdate)).name '/' files(filedate==max(filedate)).name]);
end


function PostProcessData(varargin)
%% Creates the Graphical User Interface for data processing
if nargin ==0
else
end
gui.nobuttons        = [4 6];       
gui.buttondistance   = [20 10];
gui.buttonsize       = [120 45];
gui.figuresize       = (gui.buttonsize+gui.buttondistance).*(gui.nobuttons)+gui.buttondistance;
gui.uipositions(:,1) = sort(repmat(round(linspace(gui.buttondistance(1),gui.figuresize(1)-gui.buttondistance(1)-gui.buttonsize(1),gui.nobuttons(1))'),gui.nobuttons(2),1));
gui.uipositions(:,2) = repmat(round(linspace(gui.buttondistance(2),gui.figuresize(2)-gui.buttondistance(2)-gui.buttonsize(2),gui.nobuttons(2))'),gui.nobuttons(1),1);

if ~isfield(gui,'fid');
    gui.fid          = figure(10);
    set(gui.fid,'name','Timer-Travel Postprocessing Toolbox, (c) Roel Stijl','numbertitle','off')
    set(gui.fid,'position',[50 50 gui.figuresize]); else figure(gui.fid);
end

%% Builds the gui controls
if ~isfield(gui,'source');
    
gui.h.Runs                  = uicontrol('String','1','Style','edit');
gui.h.Regions               = uicontrol('String','12','Style','edit');
gui.h.ErrorThreshold        = uicontrol('String','inf','Style','edit'); % Determines at what threshold data hsould be left out, (icw FilterOutput)

gui.h.RegionSet             = uicontrol('Style','popupmenu','String',{'regions26','regions11','regions3'},'Value',2);
gui.h.ModeSet               = uicontrol('Style','popupmenu','String',{'modes7','modes4'},'Value',2);

gui.h.FilterOutput          = uicontrol('Style','checkbox','value',0); %
gui.h.SaveExcelOutput       = uicontrol('Style','checkbox','value',0); % 

gui.h.AllRuns               = uicontrol('Style','checkbox','value',1); % 
gui.h.AllRegions            = uicontrol('Style','checkbox','value',0); % 

gui.h.Selectbestrun         = uicontrol('Style','checkbox','value',0); % 
gui.h.Removeoutliers        = uicontrol('Style','checkbox','value',0); % 

gui.h.SingleRunAnalysis     = uicontrol('Style','popupmenu','String',{'None','Single Plot','HistoricPlot','ProjectionPlot','AllYearsPlot','ProjectionArea','Regression and Scatter','Sensitivity Analysis','TTB and TMB','PF or SW over time'});
gui.h.SingleRunMultiRegion  = uicontrol('Style','popupmenu','String',{'None','Barplot depvars','Barplot indepvars','Barplot errors'});
gui.h.MultiRunAnalysis      = uicontrol('Style','popupmenu','String',{'None','Scatter Plots, independant errors','Scatter Plots, errors added','Scatter plots, select variables','Probablistic Projection','CO2 and Energy all regions','CO2 and Energy intensity projections','AllYearsProbablistic','BoxPlots of NRSME','BoxPlot of indepvars','BoxPlot of indepvar per mode','Send to workspace'});
gui.h.MultiFileAnalysis     = uicontrol('Style','popupmenu','String',{'None','Probablistic 4 regions','Boxplot all regions'});
gui.h.PlotExportType        = uicontrol('Style','popupmenu','String',{'Default','A4','Publication Tiny','Publication Small Flat','Publication Small','Publication Large' });
gui.h.LoadLastRun           = uicontrol('Style','togglebutton','String','Load last run data','Value',1);
gui.h.ReloadData            = uicontrol('Style','togglebutton','String','ReloadData','Value',1);
gui.h.Process               = uicontrol('Style','togglebutton','String','Process');

gui.h.MergeFiles            = uicontrol('Style','edit','String','1');
gui.h.OutputFolder          = uicontrol('Style','edit','String','Temporary');
gui.h.OutputFile            = uicontrol('Style','edit','String','');

end

gui.configs.startdate           = get(gui.h.OutputFolder,'String');

%% Modify GUI positions
gui.uifields          = fieldnames(gui.h);
gui.checkboxcount     = 1; n=1; m=1;
while n<=length(gui.uifields);
switch get(gui.h.(char(gui.uifields(n,:))),'Style')
    case 'checkbox'
        set(gui.h.(char(gui.uifields(n,:))),'String',char(gui.uifields(n,:)),'position',[gui.uipositions(m,1) gui.uipositions(m,2)+gui.buttonsize(2)*mod(gui.checkboxcount+1,2)/2 gui.buttonsize(1) gui.buttonsize(2)/2]);
        m=m-mod(gui.checkboxcount,2); gui.checkboxcount = gui.checkboxcount+1;
        if ~isequal(get(gui.h.(char(gui.uifields(n+1,:))),'Style'),'checkbox')&&mod(m,2)~=0; m=m+1; end
    case {'edit'}
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize(1),gui.buttonsize(2)/2]);
        uicontrol('Style','text','String',char(gui.uifields(n,:)),'position',[gui.uipositions(m,1) gui.uipositions(m,2)+gui.buttonsize(2)/2 gui.buttonsize(1) gui.buttonsize(2)/2],'Backgroundcolor',get(gui.fid,'color'))
    case {'popupmenu'}
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize(1),gui.buttonsize(2)/2]);
        uicontrol('Style','text','String',char(gui.uifields(n,:)),'position',[gui.uipositions(m,1) gui.uipositions(m,2)+gui.buttonsize(2)/2 gui.buttonsize(1) gui.buttonsize(2)/2],'Backgroundcolor',get(gui.fid,'color'))
        curstrings = get(gui.h.(char(gui.uifields(n,:))),'String');
        if isequal('Specify',char(curstrings(get(gui.h.(char(gui.uifields(n,:))),'Value'),:))); 
            gui.s.(char(gui.uifields(n,:))) = specifygui(gui.h.(char(gui.uifields(n,:)))); end
    case 'pushbutton'
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize]);
    otherwise
        set(gui.h.(char(gui.uifields(n,:))),'position',[gui.uipositions(m,:) gui.buttonsize]);
end
    set(gui.h.(char(gui.uifields(n,:))),'Backgroundcolor',get(gui.fid,'color'));
    n=n+1; m=m+1;
end

%% Send handles to configuration
Run([],gui);

end

function Run(guihandle,event)
%% Loads the gui controls into configs and runs the analysis
persistent gui
persistent data

if isempty(guihandle)
data        = [];
gui         = event;
set(gui.h.Process,'Value',0,'Callback',@Run);
else
    
if isempty(data) || get(gui.h.ReloadData,'Value')==1;
    if get(gui.h.LoadLastRun,'Value')==1
        data = loadlastrundata;
    elseif str2num(get(gui.h.MergeFiles,'String')) ==1
    cd Output;    
    uiopen('load');
    cd ..;
    end
    set(gui.h.ReloadData,'Value',0);
end
    
set(gui.h.Process,'Value',0,'Callback',@Run);
%% Read out gui values
cfg.h = gui.h;
for n=1:length(gui.uifields)
switch get(gui.h.(char(gui.uifields(n,:))),'Style')
    case 'checkbox'
        cfg.(char(gui.uifields(n,:))) = get(gui.h.(char(gui.uifields(n,:))),'Value');
    case 'edit'
        if sum(isletter(get(gui.h.(char(gui.uifields(n,:))),'String'))) == 0 || strcmp('inf',get(gui.h.(char(gui.uifields(n,:))),'String'))       
            cfg.(char(gui.uifields(n,:)))     = eval(['[' get(gui.h.(char(gui.uifields(n,:))),'String') ']']);
        else
            cfg.(char(gui.uifields(n,:))) = get(gui.h.(char(gui.uifields(n,:))),'String');
        end
    case 'popupmenu'
        temp.popup                    = get(gui.h.(char(gui.uifields(n,:))),'String');
        cfg.(char(gui.uifields(n,:))) = temp.popup(get(gui.h.(char(gui.uifields(n,:))),'Value'),:);
        cfg.(char(gui.uifields(n,:))) = cfg.(char(gui.uifields(n,:))){1};
    otherwise
        cfg.(char(gui.uifields(n,:))) = get(gui.h.(char(gui.uifields(n,:))),'Value');
end
end

ProcessData(cfg,gui,data);
end
end

function data = loadlastrundata
%% Loads the last saved dataset if button is pressed
    folders = dir('Output/Test');
    folderdate = zeros([1 length(folders)]);

    for n=3:length(folders)
        folderdate(n) = folders(n).datenum;
    end
    
    files = dir (['Output/Test/' folders(folderdate==max(folderdate)).name '/*.mat']);
    
    for n=1:length(files)
        filedate(n) = files(n).datenum;
    end    
    
    fullpath = ['Output/Test/' folders(folderdate==max(folderdate)).name '/'  files(filedate==max(filedate)).name];
    load(fullpath);
    disp(['Loaded: ' 'Output/Test/' folders(folderdate==max(folderdate)).name '/' files(filedate==max(filedate)).name]);
end